using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;

namespace DeveloperConsole
{
    public enum ConsoleFlags
    { 
        NONE,
        CHEAT,
    }
 
    public class ConVar
    {
        public const int UNDEFINED = -99999; 

        // local variables
        private string m_sValue;
        private string m_sKey;
        private string m_sDescription;
        private ConsoleFlags m_flags;
        private string m_sDefaultValue;

        public ConVar()
        {
            // This constructor should never be called.
            m_sKey = "";
            m_sDefaultValue = m_sValue = "";
            m_sDescription = "";
            m_flags = ConsoleFlags.NONE;
        }
        public ConVar(string key, ConsoleFlags flags, string description)
        {
            m_sKey = key;
            m_sDefaultValue = m_sValue = "";
            m_sDescription = description;
            m_flags = flags;
            ConVarMap.Singleton.CreateConVar(m_sKey, this);
        }
        public ConVar(string key, string value, ConsoleFlags flags, string description)
            : this(key, flags, description)
        {
            m_sDefaultValue = m_sValue = value;
        }
        public ConVar(string key, int value, ConsoleFlags flags, string description)
            : this(key, flags, description)
        {
            m_sDefaultValue = m_sValue = value.ToString();
        }
        public ConVar(string key, float value, ConsoleFlags flags, string description)
            : this(key, flags, description)
        {
            m_sDefaultValue = m_sValue = value.ToString();
        }
        public ConVar(string key, double value, ConsoleFlags flags, string description)
            : this(key, flags, description)
        {
            m_sDefaultValue = m_sValue = value.ToString();
        }
        public ConVar(string key, bool value, ConsoleFlags flags, string description)
            : this(key, flags, description)
        {
            m_sDefaultValue = m_sValue = value.ToString();
        }

        public int GetInt()
        {
            if (string.IsNullOrEmpty(m_sValue) || IsNaN())
                return UNDEFINED;
            return Convert.ToInt32(m_sValue);
        }
        public double GetDouble()
        {
            if (string.IsNullOrEmpty(m_sValue) || IsNaN())
                return UNDEFINED;
            return Convert.ToDouble(m_sValue);
        }
        public float GetFloat()
        {
            if (string.IsNullOrEmpty(m_sValue) || IsNaN())
                return UNDEFINED;
            return (float)Convert.ToDouble(m_sValue);
        }
        public bool GetBool()
        {
            if (!string.IsNullOrEmpty(m_sValue))
            {
                if (!IsNaN() )
                    return GetFloat() > 0 ? true : false;
                else if (m_sValue.ToLower().Equals("true") || m_sValue.ToLower().Equals("false") )
                    return Convert.ToBoolean(m_sValue);
            }
            return false;
        }
        public string GetString()
        {
            return m_sValue;
        }
        public string GetKey()
        {
            return m_sKey;
        }
        public string GetDefaultValue()
        {
            return m_sDefaultValue;
        }
        public string GetDescription()
        {
            return m_sDescription;
        }
        public ConsoleFlags GetFlags()
        {
            return m_flags;
        }

        public bool SetValue(string value)
        {
            if (!string.IsNullOrEmpty(value))
            {
                m_sValue = value;
                return true;
            }
            return false;
        }
        public bool SetValue(float value)
        {
            m_sValue = value.ToString();
            return true;
        }
        public bool SetValue(int value)
        {
            m_sValue = value.ToString();
            return true;
        }
        public bool SetValue(double value)
        {
            m_sValue = value.ToString();
            return true;
        }
        public bool SetValue(bool value)
        {
            m_sValue = value.ToString();
            return true;
        }
        public bool IsNaN()
        {
            float result;
            return !float.TryParse(m_sValue, out result);
        }
    }

    public sealed class ConVarMap
    {
        private static readonly ConVarMap instance = new ConVarMap();
        private static Dictionary<string, ConVar> m_Map = new Dictionary<string, ConVar>();

        private ConVarMap() { }

        public static ConVarMap Singleton
        {
            get
            {
                return instance;
            }
        }
        public bool CreateConVar(string key, ConVar value)
        {
            if (m_Map == null)
                m_Map = new Dictionary<string, ConVar>();
            if (!string.IsNullOrEmpty(key))
            {
                m_Map.Add(key, value);
                return true;
            }
            return false;
        }
        public ConVar GetConVar(string key)
        {
            if (m_Map.ContainsKey(key))
                return m_Map[key];
            return null;
        }
        public bool SetConVar(string key, string value)
        {
            if (m_Map.ContainsKey(key))
            {
                return m_Map[key].SetValue(value);
            }
            return false;
        }

        // Only detects complete/exact string. No variation atm.
        public List<string> Find(string key)
        {
            List<string> theKeys = new List<string>();
            foreach (KeyValuePair<string, ConVar> pair in m_Map)
            {
                if (pair.Value.GetString().Contains(key) ||
                    pair.Value.GetDescription().Contains(key)||
                    pair.Key.Contains(key))
                    theKeys.Add(pair.Key);
            }
            return theKeys;
        }
        public List<string> Keys()
        {
            List<string> theKeys = new List<string>();
            foreach (KeyValuePair<string, ConVar> pair in m_Map)
            {
                theKeys.Add(pair.Key);
            }
            return theKeys;
        }
    }
}